/**
 * 
 * Copyright (C) 2011 Cody Stoutenburg . All rights reserved.
 *
 *       This program is free software; you can redistribute it and/or
 *       modify it under the terms of the GNU Lesser General Public License
 *       as published by the Free Software Foundation; either version 2.1
 *       of the License, or (at your option) any later version.
 *
 *       This program is distributed in the hope that it will be useful,
 *       but WITHOUT ANY WARRANTY; without even the implied warranty of
 *       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *       GNU Lesser General Public License for more details.
 *
 *       You should have received a copy of the GNU Lesser General Public License
 *       along with this program; if not, write to the Free Software
 *       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. 
 * 
 */
package ca.usherbrooke.mainApp.view.openSimulation;

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import ca.usherbrooke.agent.controller.shared.IAgent;
import ca.usherbrooke.mainApp.MainAppAgent;
import ca.usherbrooke.mainApp.view.PackageObject;
import ca.usherbrooke.mainApp.view.utils.cellRender.EntityListCellRender;
import ca.usherbrooke.mainApp.view.utils.cellRender.PackageObjectCellRender;
import ca.usherbrooke.mainApp.view.utils.cellRender.ResultCellRender;
import ca.usherbrooke.model.entity.IEntityModel;
import ca.usherbrooke.model.world.IWorldModel;
import ca.usherbrooke.utils.ExternalClassLoad;

/**
 * @author Cody Stoutenburg
 * 
 */
public class PanelMapAgentEntity extends JPanel {
	private static final long serialVersionUID = 1L;

	private static final String ALL_PACKAGE_SELECTED = "(all)";

	private final JList listPackage;
	private final JList listAgent;
	private final JList listEntity;
	private final JList listEntityAgent;

	private final DefaultListModel listPackageModel;
	private final DefaultListModel listAgentModel;
	private final DefaultListModel listEntityModel;
	private final DefaultListModel listEntityAgentModel;

	public PanelMapAgentEntity(IWorldModel world) {
		this.setLayout(new GridLayout(1, 4));

		listPackageModel = new DefaultListModel();
		listAgentModel = new DefaultListModel();
		listEntityModel = new DefaultListModel();
		listEntityAgentModel = new DefaultListModel();

		listPackage = new JList(listPackageModel);
		listPackage.setCellRenderer(new PackageObjectCellRender());
		listPackage.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		listPackage.addListSelectionListener(new ListSelectionListener() {
			@Override
			public void valueChanged(ListSelectionEvent e) {
				refreshAgent();
			}
		});

		listAgent = new JList(listAgentModel);
		listAgent.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

		listEntity = new JList(listEntityModel);
		listEntity.setCellRenderer(new EntityListCellRender());
		listEntity.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

		listEntityAgent = new JList(listEntityAgentModel);
		listEntityAgent.setCellRenderer(new ResultCellRender());
		listEntityAgent
				.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);

		JPanel panelListPackage = new JPanel();
		panelListPackage
				.setBorder(BorderFactory.createTitledBorder("Packages"));
		panelListPackage.add(listPackage);

		JPanel panelListAgent = new JPanel();
		panelListAgent.setBorder(BorderFactory.createTitledBorder("Agents"));
		panelListAgent.add(listAgent);

		JPanel panelListEntity = new JPanel();
		panelListEntity.setBorder(BorderFactory.createTitledBorder("Entities"));
		panelListEntity.add(listEntity);

		JPanel panelListEntityAgent = new JPanel();
		panelListEntityAgent.setBorder(BorderFactory
				.createTitledBorder("Agent/Entity Selected"));
		panelListEntityAgent.add(listEntityAgent);

		JPanel panelAddRemove = new JPanel();
		panelAddRemove
				.setLayout(new BoxLayout(panelAddRemove, BoxLayout.Y_AXIS));

		JButton addEntityAgent = new JButton("Add ->");
		addEntityAgent.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				addEntityAgent();
			}
		});
		JButton removeEntityAgent = new JButton("<- Remove");
		removeEntityAgent.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				removeEntityAgent();
			}
		});
		panelAddRemove.add(addEntityAgent);
		panelAddRemove.add(removeEntityAgent);

		this.add(panelListPackage);
		this.add(panelListAgent);
		this.add(panelListEntity);

		this.add(panelAddRemove);

		this.add(panelListEntityAgent);

		// load all entities we do it ones, it can't change when loading
		List<IEntityModel> allEntities = world.getAllEntities();
		for (IEntityModel entity : allEntities) {
			listEntityModel.addElement(entity);
		}

		refreshPackages();
		this.revalidate();
	}

	// /////////////// refresh methods //////////////////////
	private void refreshPackages() {
		listPackageModel.removeAllElements();

		listPackageModel.addElement(new PackageObject(ALL_PACKAGE_SELECTED,
				null));

		List<PackageObject> allPackages = getPackageName(MainAppAgent.DIRECTORY_AGENT);
		for (PackageObject packageName : allPackages) {
			listPackageModel.addElement(packageName);
		}

		listPackage.setSelectedIndex(0);
	}

	private void addListAgent(PackageObject packageInfo) {
		PackageObject packageSelected = getSelectedPackage();

		File[] files = packageInfo.getDirectory().listFiles();

		for (File file : files) {
			if (!file.isDirectory()) {
				String shortName = file.getName().split(".class")[0];
				String completeName = packageInfo.getName() + "." + shortName;
				if (ExternalClassLoad.verifyClass(MainAppAgent.DIRECTORY_AGENT,
						IAgent.class, completeName, false)) {
					if (packageSelected.getName().equals(ALL_PACKAGE_SELECTED)) {
						listAgentModel.addElement(completeName);
					} else {
						listAgentModel.addElement(shortName);
					}
				}
			}
		}
	}

	private PackageObject getSelectedPackage() {
		return (PackageObject) listPackage.getSelectedValue();
	}

	private IEntityModel getSelectedEntityModel() {
		return (IEntityModel) this.listEntity.getSelectedValue();
	}

	private String getSelectedAgent() {
		String result = "";
		PackageObject packageSelected = getSelectedPackage();
		if (packageSelected != null) {
			if (packageSelected.getName().equals(ALL_PACKAGE_SELECTED)) {
				result = (String) this.listAgent.getSelectedValue();
			} else {
				result = packageSelected.getName() + "."
						+ this.listAgent.getSelectedValue();
			}
		}
		return result;
	}

	private List<PackageObject> getPackageName(File root) {
		List<PackageObject> allPackages = new ArrayList<PackageObject>();
		File[] allFiles = root.listFiles();
		for (File f : allFiles) {
			if (f.isDirectory()) {
				allPackages.addAll(getPackageName(f, ""));
			} else {
				allPackages.add(new PackageObject(root.getName(), root));
			}
		}

		return allPackages;
	}

	private List<PackageObject> getPackageName(File root, String path) {
		List<PackageObject> allPackages = new ArrayList<PackageObject>();

		Boolean haveFile = false;
		File[] files = root.listFiles();
		for (File file : files) {
			if (file.isDirectory()) {
				allPackages.addAll(getPackageName(file, path + root.getName()
						+ "."));
			} else if (!haveFile) {
				String className = ExternalClassLoad
						.toClassName(file.getName());
				if (ExternalClassLoad.verifyClass(MainAppAgent.DIRECTORY_AGENT,
						IAgent.class, path + root.getName() + "." + className,
						false)) {
					haveFile = true;
				}
			}
		}

		if (haveFile) {
			allPackages.add(new PackageObject(path + root.getName(), root));
		}
		return allPackages;
	}

	// ///////////////// METHODS CALLBACK //////////////////////
	private void refreshAgent() {
		listAgentModel.removeAllElements();
		PackageObject packageSelected = (PackageObject) listPackage
				.getSelectedValue();
		if (packageSelected != null) {
			if (packageSelected.getName().equals(ALL_PACKAGE_SELECTED)) {
				List<PackageObject> allPackages = getPackageName(MainAppAgent.DIRECTORY_AGENT);

				for (PackageObject string : allPackages) {
					addListAgent(string);
				}

			} else {
				addListAgent(packageSelected);
			}

		}
		listAgent.setSelectedIndex(0);
		this.revalidate();
	}

	private void addEntityAgent() {
		this.listEntityAgentModel.addElement(new EntityAgentObject(
				getSelectedAgent(), getSelectedEntityModel()));

		this.listEntityModel.remove(this.listEntity.getSelectedIndex());
	}

	private void removeEntityAgent() {
		Object[] allEntityAgent = this.listEntityAgent.getSelectedValues();
		int[] selected = listEntityAgent.getSelectedIndices();

		for (Object entityAgentObject : allEntityAgent) {
			this.listEntityModel
					.addElement(((EntityAgentObject) entityAgentObject)
							.getEntity());
		}

		for (int idx : selected) {
			this.listEntityAgentModel.remove(idx);
		}
	}

	// ///////////////// PUBLIC GETTER /////////////////////////
	public Map<IEntityModel, String> getAgentForEntities() {
		HashMap<IEntityModel, String> result = new HashMap<IEntityModel, String>();

		for (int i = 0; i < listEntityAgentModel.size(); ++i) {
			EntityAgentObject obj = (EntityAgentObject) listEntityAgentModel
					.get(i);
			result.put(obj.getEntity(), obj.getAgent());
		}

		return result;
	}

	public Boolean isAllEntitySelected() {
		return listEntityModel.size() == 0;
	}
}
